﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
/*
 * Helper methods for List functionality
 * 
 * A list consists of a set of key-value pairs.  There are four accounting fields for a list:
 *      _<listName>_count: The current length of the list
 *      _<listName>_left: The index associated with the left-hand element of the list
 *      _<listName>_right: The index associated with the right-hand element of the list
 *      _<listName>_nextAddress: The index to use for the next node
 * 
 * In addition, each element in the list is represented by a key-value pair with the 
 * element index encoded into the key, and the value being a tuple of the form <element value, previous index, next index>.
 * 
 * So, for example, a list that was formed by the sequence "Push list1 left one", "Push list1 left zero", "Push list1 right two"
 * would be represented internally with the following key-value pairs:
 * 
 *      "_<listName>_count" => 3
 *      "_<listName>_left" => 1
 *      "_<listName>_right" => 2
 *      "_<listName>_nextAddress" => 3
 *      "_<listName>$_0" => <"one",1,2>
 *      "_<listName>$_1" => <"zero",-1,0>
 *      "_<listName>$_2" => <"two",0,-1>
 *      
 * If you update these names, update the helper methods below.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Collections.Specialized;
using System.Threading.Tasks;
using System.Threading.Actors;
using System.Collections;

namespace System.Threading.Actors.Helpers
{
    public static class ListHelperMethods
    {
        public const string MyTypeName = "LIST";

        //
        // Some utility methods to enforce consistent naming of keys among methods
        //

        private static string ElementKeyName(string listName, int index)
        {
            return String.Format("_{0}$_{1}", listName, index);
        }

        private static string LeftIndexKeyName(string listName)
        {
            return String.Format("_{0}_left", listName);
        }

        private static string RightIndexKeyName(string listName)
        {
            return String.Format("_{0}_right", listName);
        }

        private static string CountKeyName(string listName)
        {
            return String.Format("_{0}_count", listName);
        }

        private static string NextIndexKeyName(string listName)
        {
            return String.Format("_{0}_nextIndex", listName);
        }

        private static string ElementPrefix(string listName)
        {
            return '_' + listName + "$_";
        }

        private static string AllowPublishKeyName(string listName)
        {
            return String.Format("_{0}_allowPub", listName);
        }

        // This is for storing delegates as fields within an instance of a list.  Do not think of this as an instance
        // method on a type.  
        private static string DelegateKeyName(string listName, string methodName)
        {
            return String.Format("_{0}$Delegate${1}", listName, methodName);
        }


        // Look up methods for doing equality and comparisons from the actor state.
        // Also for generality, do not require that these are set.
        private static Func<Object, Object, bool> GetEqualityMethod(IActorState astate, String listName)
        {
            String equalsKey = DelegateKeyName(listName, "Equals");
            Func<Object, Object, bool> equalsMethod;
            Object foundMethod;
            if (astate.TryGet(equalsKey, out foundMethod))
                equalsMethod = (Func<Object, Object, bool>)foundMethod;
            else
                equalsMethod = Object.Equals;
            return equalsMethod;
        }

        private static Comparison<Object> GetCompareMethod(IActorState astate, String listName)
        {
            String compareKey = DelegateKeyName(listName, "Compare");
            Comparison<Object> compareMethod;
            Object foundMethod;
            if (astate.TryGet(compareKey, out foundMethod))
                compareMethod = (Comparison<Object>)foundMethod;
            else
                compareMethod = Comparer.Default.Compare;
            return compareMethod;
        }

        public static void LoadActorMethods(IActorState state)
        {
            Contract.Requires(state != null);

            object temp;
            if (state.TryGet("TryConstruct", out temp)) return;

            state.Set("Push", (Func<IActorState, object[], object>)Push);
            state.Set("PushD", (Func<dynamic, dynamic[], object>)PushD);
            state.Set("GetAt", (Func<IActorState, object[], object>)GetAt);
            state.Set("Length", (Func<IActorState, object[], object>)Length);
            state.Set("Pop", (Func<IActorState, object[], object>)Pop);
            state.Set("Enumerate", (Func<IActorState, object[], object>)Enumerate);
            state.Set("Clear", (Func<IActorState, object[], object>)Clear);
            state.Set("Destroy", (Func<IActorState, object[], object>)Destroy);
            state.Set("AddOnce", (Func<IActorState, object[], object>)AddOnce);
            state.Set("UpdateItemAt", (Func<IActorState, object[], object>)UpdateItemAt);
            state.Set("IndexOf", (Func<IActorState, object[], object>)IndexOf);
            state.Set("InsertAt", (Func<IActorState, object[], object>)InsertAt);
            state.Set("IsReadOnly", (Func<IActorState, object[], object>)IsReadOnly);
            state.Set("Remove", (Func<IActorState, object[], object>)Remove);
            state.Set("RemoveAt", (Func<IActorState, object[], object>)RemoveAt);
            state.Set("RemoveRange", (Func<IActorState, object[], object>)RemoveRange);
            state.Set("Sort", (Func<IActorState, object[], object>)Sort);
            state.Set("Trim", (Func<IActorState, object[], object>)RemoveRange);
            // TODO: InsertRelativeToValue

            state.Set("TryConstruct", (Func<IActorState, object[], object>)TryConstruct);
        }

        // If the list doesn't exist, set the appropriate fields.  Else, do nothing.
        // Parameters:
        //      0: list name
        // Returns:
        //      Boolean indicating whether we created a new list.
        public static Object TryConstruct(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 1);

            String listName = (String)parameters[0];
            String countKey = CountKeyName(listName);

            bool exists = ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true);
            if (!exists)
            {
                Object existingCount;
                if (!astate.TryGet(countKey, out existingCount))
                {
                    String indexerKey = NextIndexKeyName(listName);
                    String leftIndexKey = LeftIndexKeyName(listName);
                    String rightIndexKey = RightIndexKeyName(listName);
                    String compareKey = DelegateKeyName(listName, "Compare");
                    String equalsKey = DelegateKeyName(listName, "Equals");
                    String allowPublish = AllowPublishKeyName(listName);

                    astate.Set(countKey, 0);
                    astate.Set(indexerKey, 0);
                    astate.Set(leftIndexKey, -1);
                    astate.Set(rightIndexKey, -1);
                    astate.Set(allowPublish, 1);

                    // If we don't have Compare and Equals methods, add them.
                    Object tmpObj;
                    if (!astate.TryGet(compareKey, out tmpObj))
                        astate.Set(compareKey, (Comparison<Object>)Comparer.Default.Compare);
                    if (!astate.TryGet(equalsKey, out tmpObj))
                        astate.Set(equalsKey, (Func<Object, Object, bool>)Object.Equals);
                }
                ActorKeyType.SetKeyType(astate, listName, MyTypeName);
            
                return true;
            }

            return false;
        }

        // Removes the list completely.  New clients should call TryConstruct again to use it,
        // though our list actor supports clients simply jumping into using the data structure.
        // Parameters:
        //      0: list name
        // Returns:
        //      void
        public static Object Destroy(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);

            if (parameters.Length != 1)
                throw new ArgumentException(String.Format("Expected {0} parameter.", 1));

            String listName = (String)parameters[0];
            if (!ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true))
            {
                return null;
            }

            Clear(astate, parameters);

            String countKey = CountKeyName(listName);
            String indexerKey = NextIndexKeyName(listName);
            String leftIndexKey = LeftIndexKeyName(listName);
            String rightIndexKey = RightIndexKeyName(listName);
            String compareKey = DelegateKeyName(listName, "Compare");
            String equalsKey = DelegateKeyName(listName, "Equals");
            String allowPublish = AllowPublishKeyName(listName);

            astate.Remove(countKey);
            astate.Remove(indexerKey);
            astate.Remove(leftIndexKey);
            astate.Remove(rightIndexKey);
            astate.Remove(compareKey);
            astate.Remove(equalsKey);
            astate.Remove(allowPublish);
            ActorKeyType.RemoveKeyType(astate, listName);

            return null;
        }

        // Parameters:
        //      0: list name
        //      1: "left" or "right", signifying the side of the list to which to push an item
        //      2-...: value(s) to add to list
        // Returns:
        //      integer new list count if successful
        //      error string if unsuccessful
        public static object Push(IActorState astate, object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length >= 2);

            object tempObject;
            var listName = (string)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true);
            var pushLeft = ((string)parameters[1]).ToLower() == "left";
            int nextMemoryLocation = 0;
            int totalCount = 0;

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);
            string allowPublish = AllowPublishKeyName(listName);

            bool canPublish = GetAllowPublish(astate, listName);

            for (int i = 2; i < parameters.Length; i++)
            {
                var newItem = parameters[i];

                int listCount = 0;
                if (astate.TryGet(countKey, out tempObject))
                {
                    listCount = (int)tempObject;
                }

                if (listCount == 0)
                {
                    // Initialization
                    var newEntry = Tuple.Create(newItem, -1, -1);
                    ActorKeyType.SetKeyType(astate, listName, MyTypeName);
                    nextMemoryLocation = 0;
                    astate.Set(ElementKeyName(listName, nextMemoryLocation), newEntry);
                    astate.Set(countKey, 1);
                    astate.Set(leftIndexKey, nextMemoryLocation);
                    astate.Set(rightIndexKey, nextMemoryLocation);
                    astate.Set(indexerKey, nextMemoryLocation + 1);
                    totalCount = 1;

                    if (canPublish)
                        astate.Publish("Collection.ElementAdded", newItem, 0);
                }
                else
                {
                    if (astate.TryGet(indexerKey, out tempObject))
                    {
                        nextMemoryLocation = (int)tempObject;
                    }
                    var newEntryKey = ElementKeyName(listName, nextMemoryLocation);

                    if (pushLeft)
                    {
                        int leftIndex = 0;
                        if (astate.TryGet(leftIndexKey, out tempObject))
                        {
                            leftIndex = (int)tempObject;
                            var leftItemKey = ElementKeyName(listName, leftIndex);
                            if (astate.TryGet(leftItemKey, out tempObject))
                            {
                                var oldLeft = (Tuple<object, int, int>)tempObject;
                                var oldLeftAltered = Tuple.Create(oldLeft.Item1, nextMemoryLocation, oldLeft.Item3);
                                astate.Set(leftItemKey, oldLeftAltered);
                                var newEntry = Tuple.Create(newItem, -1, leftIndex);
                                astate.Set(newEntryKey, newEntry);
                                astate.Set(leftIndexKey, nextMemoryLocation);
                                astate.Set(countKey, listCount + 1);
                                astate.Set(indexerKey, nextMemoryLocation + 1);
                                totalCount = listCount + 1;
                                if (canPublish)
                                    astate.Publish("Collection.ElementAdded", newItem, 0);
                            }
                            else
                            {
                                Trace.WriteLine("ERROR:Internal:Push failed to grab left value", "Error");
                                break;
                            }
                        }
                        else
                        {
                            Trace.WriteLine("ERROR:Internal:Push failed to grab left index", "Error");
                            break;
                        }
                    }
                    else
                    {
                        int rightIndex = 0;
                        if (astate.TryGet(rightIndexKey, out tempObject))
                        {
                            rightIndex = (int)tempObject;
                            var rightItemKey = ElementKeyName(listName, rightIndex);
                            if (astate.TryGet(rightItemKey, out tempObject))
                            {
                                var oldRight = (Tuple<object, int, int>)tempObject;
                                var oldRightAltered = Tuple.Create(oldRight.Item1, oldRight.Item2, nextMemoryLocation);
                                astate.Set(rightItemKey, oldRightAltered);
                                var newEntry = Tuple.Create(newItem, rightIndex, -1);
                                astate.Set(newEntryKey, newEntry);
                                astate.Set(rightIndexKey, nextMemoryLocation);
                                astate.Set(countKey, listCount + 1);
                                astate.Set(indexerKey, nextMemoryLocation + 1);
                                totalCount = listCount + 1;
                                if (canPublish)
                                    astate.Publish("Collection.ElementAdded", newItem, listCount);
                            }
                            else
                            {
                                Trace.WriteLine("ERROR:INTERNAL:Push failed to grab right value", "Error");
                                break;
                            }
                        }
                        else
                        {
                            Trace.WriteLine("ERROR:Internal:Push failed to grab right index", "Error");
                            break;
                        }
                        
                    }
                }
            }

            return totalCount;
        }

        // Functionally equivalent to Push, but written in dynamic style.
        public static object PushD(dynamic astate, dynamic[] parameters)
        {
            string listName = parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true);
            var pushLeft = ((string)parameters[1]).ToLower() == "left";
            int nextMemoryLocation = 0;
            int totalCount = 0;

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);
            string allowPublish = AllowPublishKeyName(listName);

            bool canPublish = GetAllowPublish(astate, listName);

            for (int i = 2; i < parameters.Length; i++)
            {
                object newItem = parameters[i];

                int listCount = astate.ValueOrDefault(countKey, 0);

                if (listCount == 0)
                {
                    // Initialization
                    var newEntry = Tuple.Create(newItem, -1, -1);
                    ActorKeyType.SetKeyType(astate, listName, MyTypeName);
                    nextMemoryLocation = 0;
                    astate[ElementKeyName(listName, nextMemoryLocation)] = newEntry;
                    astate[countKey] = 1;
                    astate[leftIndexKey] = nextMemoryLocation;
                    astate[rightIndexKey] = nextMemoryLocation;
                    astate[indexerKey] = nextMemoryLocation + 1;
                    totalCount = 1;
                    if (canPublish)
                        astate.Publish("Collection.ElementAdded", newItem, 0);
                }
                else
                {
                    nextMemoryLocation = astate.ValueOrDefault(indexerKey, 0);
                    var newEntryKey = ElementKeyName(listName, nextMemoryLocation);

                    if (pushLeft)
                    {
                        if(astate.Contains(leftIndexKey))
                        {
                            int leftIndex = astate[leftIndexKey];
                            var leftItemKey = ElementKeyName(listName, leftIndex);
                            if(astate.Contains(leftItemKey))
                            {
                                var oldLeft = (Tuple<object, int, int>) astate[leftItemKey];
                                var oldLeftAltered = Tuple.Create(oldLeft.Item1, nextMemoryLocation, oldLeft.Item3);
                                astate[leftItemKey] = oldLeftAltered;
                                var newEntry = Tuple.Create(newItem, -1, leftIndex);
                                astate[newEntryKey] = newEntry;
                                astate[leftIndexKey] = nextMemoryLocation;
                                astate[countKey] = listCount + 1;
                                astate[indexerKey] = nextMemoryLocation + 1;
                                totalCount = listCount + 1;
                                if (canPublish)
                                    astate.Publish("Collection.ElementAdded", newItem, 0);
                            }
                            else
                            {
                                Trace.WriteLine("ERROR:Internal:Push failed to grab left value", "Error");
                                break;
                            }
                        }
                        else
                        {
                            Trace.WriteLine("ERROR:Internal:Push failed to grab left index", "Error");
                            break;
                        }
                    }
                    else
                    {
                        if(astate.Contains(rightIndexKey))
                        {
                            int rightIndex = astate[rightIndexKey];
                            var rightItemKey = ElementKeyName(listName, rightIndex);
                            if(astate.Contains(rightItemKey))
                            {
                                var oldRight = (Tuple<object, int, int>) astate[rightItemKey];
                                var oldRightAltered = Tuple.Create(oldRight.Item1, oldRight.Item2, nextMemoryLocation);
                                astate[rightItemKey] = oldRightAltered;
                                var newEntry = Tuple.Create(newItem, rightIndex, -1);
                                astate[newEntryKey] = newEntry;
                                astate[rightIndexKey] = nextMemoryLocation;
                                astate[countKey] = listCount + 1;
                                astate[indexerKey] = nextMemoryLocation + 1;
                                totalCount = listCount + 1;
                                if (canPublish)
                                    astate.Publish("Collection.ElementAdded", newItem, listCount);
                            }
                            else
                            {
                                Trace.WriteLine("ERROR:INTERNAL:Push failed to grab right value", "Error");
                                break;
                            }
                        }
                        else
                        {
                            Trace.WriteLine("ERROR:Internal:Push failed to grab right index", "Error");
                            break;
                        }

                    }
                }
            }

            return totalCount;
        }

        // Parameters:
        //      0: list name
        //      1: "right" or "left", to signify the side of the list from which to pop
        // Returns:
        //      object popped value if successful
        //      error string if unsuccessful
        public static object Pop(IActorState astate, object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 2);
			
            object tempObject;
            var listName = (string)parameters[0];
            if (!ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true))
            {
                return null; // return "nil" for non-existent key
            }
            var popLeft = ((string)parameters[1]).ToLower() == "left";

            var countKey = CountKeyName(listName);
            var leftIndexKey = LeftIndexKeyName(listName);
            var rightIndexKey = RightIndexKeyName(listName);
            var indexerKey = NextIndexKeyName(listName);

            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            if (listCount == 0)
            {
                throw new InvalidOperationException("Attempted to Pop from empty list " + listName);
            }
            else
            {
                if (popLeft)
                {
                    int leftIndex = 0;
                    if (astate.TryGet(leftIndexKey, out tempObject))
                    {
                        leftIndex = (int)tempObject;
                        var leftValueKey = ElementKeyName(listName, leftIndex);
                        if (astate.TryGet(leftValueKey, out tempObject))
                        {
                            var oldLeft = (Tuple<object, int, int>)tempObject;
                            var rval = oldLeft.Item1;
                            astate.Remove(leftValueKey);
                            int newCount = listCount - 1;
                            if (newCount == 0)
                            {
                                astate.Set(leftIndexKey, -1);
                                astate.Set(rightIndexKey, -1);
                                astate.Set(countKey, 0);
                                astate.Set(indexerKey, 0); // Go ahead and reset the "next index" value when the list gets emptied
                            }
                            else
                            {
                                astate.Set(leftIndexKey, oldLeft.Item3);
                                astate.Set(countKey, newCount);
                                // Null out the "prev" pointer in the new left-most key
                                var newLeftKey = ElementKeyName(listName, oldLeft.Item3);
                                if (astate.TryGet(newLeftKey, out tempObject))
                                {
                                    var oldLeftValue = (Tuple<object, int, int>)tempObject;
                                    var newLeftValue = Tuple.Create(oldLeftValue.Item1, -1, oldLeftValue.Item3);
                                    astate.Set(newLeftKey, newLeftValue);
                                }
                                    
                            }
                            if (GetAllowPublish(astate, listName))
                                astate.Publish("Collection.ElementRemoved", rval, 0);
                            return rval;
                        }
                        else
                        {
                            throw new Exception("Internal: Pop could not read $_left value");
                        }
                    }
                    else
                    {
                        throw new Exception("Internal:Pop could not read $_left address");
                    }
                }
                else
                {
                    int rightIndex = 0;
                    if (astate.TryGet(rightIndexKey, out tempObject))
                    {
                        rightIndex = (int)tempObject;
                        var rightValueKey = ElementKeyName(listName, rightIndex);
                        if (astate.TryGet(rightValueKey, out tempObject))
                        {
                            var oldRight = (Tuple<object, int, int>)tempObject;
                            var rval = oldRight.Item1;
                            astate.Remove(rightValueKey);
                            int newCount = listCount - 1;
                            if (newCount == 0)
                            {
                                astate.Set(leftIndexKey, -1);
                                astate.Set(rightIndexKey, -1);
                                astate.Set(countKey, 0);
                                astate.Set(indexerKey, 0); // Go ahead and reset the "next index" value when the list gets emptied
                            }
                            else
                            {
                                astate.Set(rightIndexKey, oldRight.Item2);
                                astate.Set(countKey, newCount);
                                // Null out the "next" pointer in the new right-most key
                                var newRightKey = ElementKeyName(listName, oldRight.Item2);
                                if (astate.TryGet(newRightKey, out tempObject))
                                {
                                    var oldRightValue = (Tuple<object, int, int>)tempObject;
                                    var newRightValue = Tuple.Create(oldRightValue.Item1, oldRightValue.Item2, -1);
                                    astate.Set(newRightKey, newRightValue);
                                }
                            }
                            if (GetAllowPublish(astate, listName))
                                astate.Publish("Collection.ElementRemoved", rval, newCount);
                            return rval;
                        }
                        else { throw new Exception( "Internal:Pop could not read $_right address"); }
                    }
                    else { throw new Exception( "Internal:Pop could not read $_right value"); }
                }
            }

        }

        // Utility method to resolve an index parameter, which could be encoded as an int or a string.
        private static bool TryResolveIndex(object indexObject, out int index)
        {
            index = -1;
            if (indexObject is int)
            {
                index = (int)indexObject;
                return true;
            }
            else
            {
                var s = (string)indexObject;
                if (s != null)
                {
                    return Int32.TryParse(s, out index);
                }
            }

            return false;
        }

        // Parameters:
        //      0: list name
        //      1: index to examine (can be encoded as int or string)
        // Returns:
        //      object value if the operation makes sense and is successful
        //      error string if operation is unsuccessful
        public static object GetAt(IActorState astate, object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 2);

            var listName = (string)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            var index = -1;
            if (!TryResolveIndex(parameters[1], out index))
            {
                throw new ArgumentException(String.Format("GetAt failed to resolve index parameter {0}", parameters[1].ToString()));
            }

            // Defer to Range() call
            object result = Enumerate(astate, new object[] {listName, index, index});
            var list  = result as List<object>;
            if (list != null)
            {
                if (list.Count < 1)
                {
                    // .NET's List<T> throws an ArgumentOutOfRangeException.
                    throw new ArgumentOutOfRangeException(String.Format("No element found for list {0} at index {1}", listName, index));
                }
                else
                {
                    result = list[0];
                }
            }

            return result;
        }

        // Parameters: 
        //      0: listName
        // Returns:
        //      integer length if successful
        //      string error if unsuccessful
        public static object Length(IActorState astate, object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 1);

            var listName = (string)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            object tempObject;

            int listCount = 0;
            if (astate.TryGet(CountKeyName(listName), out tempObject))
            {
                listCount = (int)tempObject;
                return listCount;
            }
            else
            {
                throw new InvalidOperationException( "Length called for non-existent or uninitialized list " + listName);
            }
        }

        // Parameters:
        //      0: list name
        //      1: index "from" (inclusive)
        //      2: index "to" (inclusive)
        // Returns:
        //      List<object> if successful
        //      error string if unsuccessful
        public static object Enumerate(IActorState astate, object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 3);

            object tempObject;
            var listName = (string)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            var begin = 0;
            var end = 0;
            if(!TryResolveIndex(parameters[1], out begin))
            {
                throw new ArgumentException(String.Format("Enumerate begin parameter {0} could not be parsed as an integer", parameters[1]));
            }

            if(!TryResolveIndex(parameters[2], out end))
            {
                throw new ArgumentException(String.Format("Enumerate end parameter {0} could not be parsed as an integer", parameters[2]));
            }

            var countKey = CountKeyName(listName);
            var leftIndexKey = LeftIndexKeyName(listName);
            var rightIndexKey = RightIndexKeyName(listName);

            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }
            else
            {
                throw new InvalidOperationException("Enumerate called for non-existent or uninitialized list " + listName);
            }

            // check/adjust begin/end values
            if (begin >= listCount) return new List<object>();
            if (begin < 0)
            {
                begin += listCount;
                if (begin < 0) begin = 0;
            }
            if (end < 0)
            {
                end += listCount;
                if (end < 0) end = 0;
            }
            if (end >= listCount) end = listCount - 1;
            if (begin > end) begin = end;

            var returnList = new List<object>(end - begin + 1);

            if (astate.TryGet(leftIndexKey, out tempObject))
            {
                int leftIndex = (int)tempObject;
                int count = 0;
                var currentKey = ElementKeyName(listName, leftIndex);
                while (astate.TryGet(currentKey, out tempObject))
                {
                    var element = (Tuple<object, int, int>)tempObject;
                    if (count >= begin)
                    {
                        if (count > end) break;
                        returnList.Add(element.Item1);
                    }
                    count++;
                    leftIndex = (int)element.Item3;
                    currentKey = ElementKeyName(listName, leftIndex);
                }
                return returnList;
            }
            else throw new Exception( "Internal:Enumerate failed to grab left index for list " + listName);

        }

        public static Object Clear(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 1);

            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);

            string countKey = CountKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);

            // Clear all the elements in the IActorState for this particular list, using our list name for scoping.
			// @TODO: Consider adding an IActorState.ClearAllKeysWithPrefix method.
            String prefix = ElementPrefix(listName);
            IEnumerable<String> keys = astate.GetAllKeysWithPrefix(prefix);
            foreach (String key in keys)
                astate.Remove(prefix + key);

            astate.Set(leftIndexKey, -1);
            astate.Set(rightIndexKey, -1);
            astate.Set(countKey, 0);

            // No need to change the indexer address.
            if (GetAllowPublish(astate, listName))
                astate.Publish("Collection.Cleared", null);
            return null;
        }

        // Adds a set of items to the list if they don't already exist.  This is an O(n * m) operation.  However, it is
        // better than calling Contains then Add in a loop because it involves only one network hop, instead of 2*m.
        // The set of parameters should ideally not contain duplicates!  We'll assume it doesn't.
        // Parameters:
        //      0: list name
        //      1-...: value(s) to add to list
        // Returns:
        //      number of added items
        public static object AddOnce(IActorState astate, object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length >= 2);

            object tempObject;
            var listName = (string)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true);
            int nextMemoryLocation = 0;
            int totalCount = 0;
            int numAdded = 0;
            int originalListCount = -1;

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);
            string allowPublish = AllowPublishKeyName(listName);

            bool canPublish = GetAllowPublish(astate, listName);

            for (int i = 1; i < parameters.Length; i++)
            {
                var newItem = parameters[i];

                int listCount = 0;
                if (astate.TryGet(countKey, out tempObject))
                {
                    listCount = (int)tempObject;
                    if (originalListCount == -1)
                        originalListCount = listCount;
                }

                if (listCount == 0)
                {
                    // Initialization
                    var newEntry = Tuple.Create(newItem, -1, -1);
                    ActorKeyType.SetKeyType(astate, listName, MyTypeName);
                    nextMemoryLocation = 0;
                    astate.Set(ElementKeyName(listName, nextMemoryLocation), newEntry);
                    astate.Set(countKey, 1);
                    astate.Set(leftIndexKey, nextMemoryLocation);
                    astate.Set(rightIndexKey, nextMemoryLocation);
                    astate.Set(indexerKey, nextMemoryLocation + 1);
                    totalCount = 1;
                    numAdded = 1;

                    if (canPublish)
                        astate.Publish("Collection.ElementAdded", newItem, 0);
                }
                else
                {
                    // Check whether the item was in the list before now.
                    if ((int)ListHelperMethods.IndexOf(astate, new Object[] { listName, newItem }) >= 0)
                        continue;

                    if (astate.TryGet(indexerKey, out tempObject))
                    {
                        nextMemoryLocation = (int)tempObject;
                    }
                    var newEntryKey = ElementKeyName(listName, nextMemoryLocation);

                    int rightIndex = 0;
                    if (astate.TryGet(rightIndexKey, out tempObject))
                    {
                        rightIndex = (int)tempObject;
                        var rightItemKey = ElementKeyName(listName, rightIndex);
                        if (astate.TryGet(rightItemKey, out tempObject))
                        {
                            var oldRight = (Tuple<object, int, int>)tempObject;
                            var oldRightAltered = Tuple.Create(oldRight.Item1, oldRight.Item2, nextMemoryLocation);
                            astate.Set(rightItemKey, oldRightAltered);
                            var newEntry = Tuple.Create(newItem, rightIndex, -1);
                            astate.Set(newEntryKey, newEntry);
                            astate.Set(rightIndexKey, nextMemoryLocation);
                            astate.Set(countKey, listCount + 1);
                            astate.Set(indexerKey, nextMemoryLocation + 1);
                            totalCount = listCount + 1;
                            if (canPublish)
                                astate.Publish("Collection.ElementAdded", newItem, listCount);
                            numAdded++;
                        }
                        else
                        {
                            throw new InvalidOperationException("AddOnce failed to grab the right value.");
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("AddOnce failed to grab the right index.");
                    }
                }
            }

            return numAdded;
        }

        public static Object UpdateItemAt(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null); 
            Contract.Requires(parameters.Length == 3);

            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            int index = -1;
            if (!TryResolveIndex(parameters[1], out index))
            {
                throw new ArgumentException(String.Format("UpdateItemAt failed to resolve index parameter {0}", parameters[1].ToString()));
            }
            Object item = parameters[2];

            string countKey = CountKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);

            Object tempObject;
            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            if (index < 0)
                index += listCount;  // Consider handling negative indices by walking backwards through the list for perf.

            if (index >= listCount || index < 0)
            {
                throw new ArgumentException("Index is beyond the end of the collection.", "index");
            }

            int leftAddress = 0;
            if (astate.TryGet(leftIndexKey, out tempObject))
            {
                leftAddress = (int)tempObject;
            }
            else
            {
                throw new Exception("Internal:Could not read leftAddress");
            }

            bool canPublish = GetAllowPublish(astate, listName);

            int count = 0;
            String elementKeyName = ElementKeyName(listName, leftAddress);
            while (astate.TryGet(elementKeyName, out tempObject))
            {
                var element = (Tuple<object, int, int>)tempObject;
                if (count == index)
                {
                    Tuple<object, int, int> newElement = new Tuple<object, int, int>(item, element.Item2, element.Item3);
                    astate.Set(elementKeyName, newElement);
                    if (canPublish)
                        astate.Publish("Collection.ElementReplaced", item, element.Item1, index);
                    return null;
                }

                leftAddress = element.Item3;
                elementKeyName = ElementKeyName(listName, leftAddress);
                count++;
            }

            throw new Exception("Internal: Failed to find element of given index");
        }

        public static Object IsReadOnly(IActorState astate, Object[] parameters)
        {
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 1);

            return false;
        }

        public static Object IndexOf(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 2);

            Object tempObject;
            String listName = (String) parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            Object item = parameters[1];

            string countKey = CountKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);

            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            if (listCount == 0)
                return -1;

            int leftAddress = 0;
            if (astate.TryGet(leftIndexKey, out tempObject))
            {
                leftAddress = (int)tempObject;
            }
            else
            {
                throw new Exception("Internal:Could not read leftAddress");
            }

            Func<Object, Object, bool> equalsMethod = GetEqualityMethod(astate, listName);

            int index = 0;
            while (astate.TryGet(ElementKeyName(listName, leftAddress), out tempObject))
            {
                var element = (Tuple<object, int, int>)tempObject;
                if (item == null)
                {
                    if (element.Item1 == null)
                    {
                        return index;
                    }
                }
                else
                {
                    if (equalsMethod(item, element.Item1))
                    {
                        return index;
                    }
                }

                leftAddress = element.Item3;
                index++;
            }
            return -1;
        }

        public static Object InsertAt(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 3);

            String listName = (String) parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true);
            int index;
            if (!TryResolveIndex(parameters[1], out index))
            {
                throw new ArgumentException(String.Format("InsertAt failed to resolve index parameter {0}", parameters[1].ToString()));
            }
            Object newItem = parameters[2];

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);
            string allowPublish = AllowPublishKeyName(listName);

            object tempObject;
            int nextMemoryLocation = 0;
            if (astate.TryGet(indexerKey, out tempObject))
            {
                nextMemoryLocation = (int)tempObject;
            }

            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            bool canPublish = GetAllowPublish(astate, listName);

            // Assuming that people will not want to add to items around the end of the list, other than the very last item.
            if (index < 0)
            {
                index += listCount;
                if (index < 0) index = 0;
            }
            if (listCount == 0)
            {
                // Initialization
                var newEntry = Tuple.Create(newItem, -1, -1);
                nextMemoryLocation = 0;
                ActorKeyType.SetKeyType(astate, listName, MyTypeName);
                astate.Set(ElementKeyName(listName, nextMemoryLocation), newEntry);
                astate.Set(countKey, 1);
                astate.Set(leftIndexKey, nextMemoryLocation);
                astate.Set(rightIndexKey, nextMemoryLocation);
                astate.Set(indexerKey, nextMemoryLocation + 1);
                if (canPublish)
                    astate.Publish("Collection.ElementAdded", newItem, 0);
            }
            else if (index == listCount)
            {
                int rightAddress = (int)astate.Get(rightIndexKey);
                Splice(astate, listName, index, newItem, countKey, indexerKey, rightIndexKey, nextMemoryLocation, listCount, -1, rightAddress);
            }
            else
            {
                // Walk through to find the indexes where we need to insert into.
                int currentAddress = (int)astate.Get(leftIndexKey);
                int currentIndex = 0;
                int prevAddress = -1;
                String currentElementKey = ElementKeyName(listName, currentAddress);
                Tuple<Object, int, int> element = default(Tuple<Object, int, int>);
                while(currentIndex < index)
                {
                    if (!astate.TryGet(currentElementKey, out tempObject))
                        throw new Exception("Internal: List is corrupt.  Couldn't find element.");
                    element = (Tuple<Object, int, int>)tempObject;
                    prevAddress = currentAddress;
                    currentAddress = element.Item3;
                    currentElementKey = ElementKeyName(listName, currentAddress);
                    currentIndex++;
                }

                Splice(astate, listName, index, newItem, countKey, indexerKey, rightIndexKey, nextMemoryLocation, listCount, currentAddress, prevAddress);
            }

            return listCount + 1;
        }

        private static void Splice(IActorState astate, String listName, int index, Object newItem, string countKey, string indexerKey, string rightIndexKey, int nextMemoryLocation, int listCount, int currentAddress, int prevAddress)
        {
            Tuple<Object, int, int> element = default(Tuple<Object, int, int>);
            Object tempObject;
            if (currentAddress != -1)
            {
                String currentElementKey = ElementKeyName(listName, currentAddress);
                if (!astate.TryGet(currentElementKey, out tempObject))
                    throw new Exception("Internal: List is corrupt.  Couldn't find element.");
                element = (Tuple<Object, int, int>)tempObject;
            }
            var newEntry = Tuple.Create(newItem, prevAddress, currentAddress);
            astate.Set(ElementKeyName(listName, nextMemoryLocation), newEntry);

            if (currentAddress != -1)
            {
                if (element.Item2 != -1)
                    UpdateNextPointerInNode(astate, listName, element.Item2, nextMemoryLocation);
                else
                    astate.Set(LeftIndexKeyName(listName), nextMemoryLocation);
            }
            else if (prevAddress != -1)
            {
                UpdateNextPointerInNode(astate, listName, prevAddress, nextMemoryLocation);
            }

            if (currentAddress != -1 && currentAddress != -1)
                UpdateBackPointerInNode(astate, listName, currentAddress, nextMemoryLocation);

            if (index == listCount)
                astate.Set(rightIndexKey, nextMemoryLocation);
            astate.Set(countKey, listCount + 1);
            astate.Set(indexerKey, nextMemoryLocation + 1);
            if (GetAllowPublish(astate, listName))
                astate.Publish("Collection.ElementAdded", newItem, index);
        }

        private static void UpdateBackPointerInNode(IActorState astate, String listName, int updateAddress, int prevAddress)
        {
            Object tempObject;
            String elementKeyName = ElementKeyName(listName, updateAddress);
            if (!astate.TryGet(elementKeyName, out tempObject))
                throw new Exception(String.Format("Internal: Couldn't find element {0}", elementKeyName));

            var nextElement = (Tuple<Object, int, int>)tempObject;
            var newNextElement = Tuple.Create(nextElement.Item1, prevAddress, nextElement.Item3);
            astate.Set(elementKeyName, newNextElement);
        }

        private static void UpdateNextPointerInNode(IActorState astate, String listName, int updateAddress, int nextAddress)
        {
            Object tempObject;
            String elementKeyName = ElementKeyName(listName, updateAddress);
            if (!astate.TryGet(elementKeyName, out tempObject))
                throw new Exception(String.Format("Internal: Couldn't find element {0}", elementKeyName));

            var prevElement = (Tuple<Object, int, int>)tempObject;
            var newPrevElement = Tuple.Create(prevElement.Item1, prevElement.Item2, nextAddress);
            astate.Set(elementKeyName, newPrevElement);
        }

        public static Object Remove(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 3);

            Object tempObject;
            String listName = (String)parameters[0];
            if (!ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, true))
            {
                return 0;
            }
            int numToRemove;
            if (!TryResolveIndex(parameters[1], out numToRemove))
            {
                throw new ArgumentException(String.Format("Remove failed to resolve numToRemove parameter {0}", parameters[1].ToString()));
            }

            Object item = parameters[2];

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);

            bool removeAll = numToRemove == 0;
            bool fromLeft = numToRemove >= 0;
            if (numToRemove < 0)
                numToRemove = -numToRemove;
            int numRemoved = 0;
            
            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            bool canPublish = GetAllowPublish(astate, listName);

            Contract.Assert(fromLeft == true, "Removing starting from the right side is not yet implemented.");

            Func<Object, Object, bool> equalsMethod = GetEqualityMethod(astate, listName);

            if (listCount == 0)
            {
                return numRemoved;
            }
            else
            {
                int leftAddress = (int)astate.Get(leftIndexKey);

                int index = 0;
                while (astate.TryGet(ElementKeyName(listName, leftAddress), out tempObject))
                {
                    var element = (Tuple<object, int, int>)tempObject;
                    if (equalsMethod(item, element.Item1))
                    {
                        RemoveElement(astate, listName, leftIndexKey, rightIndexKey, leftAddress, element);
                        astate.Set(countKey, --listCount);
                        if (canPublish)
                            astate.Publish("Collection.ElementRemoved", element.Item1, index);
                        numRemoved++;
                        if (!removeAll && --numToRemove == 0)
                            return numRemoved;
                    }

                    leftAddress = element.Item3;
                    index++;
                }
                return numRemoved;
            }
        }

        private static void RemoveElement(IActorState astate, String listName, string leftIndexKey, string rightIndexKey, int leftAddress, Tuple<object, int, int> element)
        {
            if (element.Item2 == -1)
            {
                astate.Set(leftIndexKey, element.Item3);
                if (element.Item3 != -1)
                    UpdateBackPointerInNode(astate, listName, element.Item3, -1);
            }
            else
            {
                String prevKey = ElementKeyName(listName, element.Item2);
                Tuple<Object, int, int> oldLeftElement = (Tuple<Object, int, int>)astate.Get(prevKey);
                var newLeftElement = new Tuple<Object, int, int>(oldLeftElement.Item1, oldLeftElement.Item2, element.Item3);
                astate.Set(prevKey, newLeftElement);
            }

            if (element.Item3 == -1)
            {
                astate.Set(rightIndexKey, element.Item2);
                if (element.Item2 != -1)
                    UpdateNextPointerInNode(astate, listName, element.Item2, -1);
            }
            else
            {
                String nextKey = ElementKeyName(listName, element.Item3);
                Tuple<Object, int, int> oldRightElement = (Tuple<Object, int, int>)astate.Get(nextKey);
                var newRightElement = new Tuple<Object, int, int>(oldRightElement.Item1, element.Item2, oldRightElement.Item3);
                astate.Set(nextKey, newRightElement);
            }

            astate.Remove(ElementKeyName(listName, leftAddress));
        }

        public static Object RemoveAt(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 2);

            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            int index = -1;
            if (!TryResolveIndex(parameters[1], out index))
            {
                throw new ArgumentException(String.Format("RemoveAt failed to resolve index parameter {0}", parameters[1].ToString()));
            }

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);

            Object tempObject;
            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            if (listCount == 0)
            {
                return null;
            }
            else
            {
                bool canPublish = GetAllowPublish(astate, listName);

                int leftAddress = (int)astate.Get(leftIndexKey);

                int runningCount = 0;
                while (astate.TryGet(ElementKeyName(listName, leftAddress), out tempObject))
                {
                    var element = (Tuple<object, int, int>)tempObject;
                    if (runningCount == index)
                    {
                        RemoveElement(astate, listName, leftIndexKey, rightIndexKey, leftAddress, element);
                        astate.Set(countKey, --listCount);
                        if (canPublish)
                            astate.Publish("Collection.ElementRemoved", element.Item1, index);

                        // @TODO: For aesthetic reasons, we're returning the value removed here.  However, a .NET client would not use this value.
                        // It's unclear if any other clients would use this value.  It may be essentially wasted data.  Consider removing this if
                        // RemoveAt becomes a perf problem.
                        return element.Item1;
                    }

                    leftAddress = element.Item3;
                    runningCount++;
                }
                return null;
            }
        }

        // Parameters:
        //      0: list name
        //      1: start index to start removing at
        //      2: number of items to remove
        // Returns:
        //      void (null)
        public static Object RemoveRange(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 3);

            Object tempObject;
            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            int startIndex;
            if (!TryResolveIndex(parameters[1], out startIndex))
            {
                throw new ArgumentException(String.Format("RemoveRange failed to resolve startIndex parameter {0}", parameters[1].ToString()));
            }
            int numToRemove;
            if (!TryResolveIndex(parameters[2], out numToRemove))
            {
                throw new ArgumentException(String.Format("RemoveRange failed to resolve numToRemove parameter {0}", parameters[2].ToString()));
            }

            string countKey = CountKeyName(listName);
            string indexerKey = NextIndexKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);

            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }
            
            if (startIndex < 0 || startIndex > listCount)
                throw new ArgumentOutOfRangeException("startIndex", "StartIndex must be positive and refer to a location within the collection.");
            if (numToRemove < 0 || numToRemove > listCount)
                throw new ArgumentOutOfRangeException("numToRemove", "NumToRemove must be positive and less than the number of items within the collection.");
            if (listCount - startIndex < numToRemove)
                throw new ArgumentException("StartIndex and numToRemove were out of bounds for the array or numToRemove is greater than the number of elements from startIndex to the end of the source collection.");

            if (listCount == 0)
            {
                return null;
            }
            else
            {
                if (startIndex == 0 && numToRemove == listCount)
                {
                    Clear(astate, new Object[] { listName });
                    return null;
                }

                RemoveRangeHelper(astate, listName, startIndex, numToRemove);
                return null;
            }
        }

        private static void RemoveRangeHelper(IActorState astate, String listName, int startIndex, int numToRemove)
        {
            Contract.Requires(startIndex >= 0);
            Contract.Requires(numToRemove >= 0);

            if (numToRemove == 0)
                return;

            string countKey = CountKeyName(listName);
            string leftIndexKey = LeftIndexKeyName(listName);
            string rightIndexKey = RightIndexKeyName(listName);

            Object tempObject;
            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
                listCount = (int)tempObject;

            int leftAddress = 0;
            if (astate.TryGet(leftIndexKey, out tempObject))
                leftAddress = (int)tempObject;

            bool canPublish = GetAllowPublish(astate, listName);

            int currentIndex = 0;
            while (astate.TryGet(ElementKeyName(listName, leftAddress), out tempObject))
            {
                var element = (Tuple<object, int, int>)tempObject;
                if (currentIndex >= startIndex)
                {
                    RemoveElement(astate, listName, leftIndexKey, rightIndexKey, leftAddress, element);
                    astate.Set(countKey, --listCount);
                    if (canPublish)
                        astate.Publish("Collection.ElementRemoved", element.Item1, startIndex);
                    if (--numToRemove == 0)
                        return;
                }

                leftAddress = element.Item3;
                currentIndex++;
            }
            throw new InvalidOperationException(String.Format("List was corrupted - could not find index {0}", leftAddress));
        }


        // Parameters:
        //      0: list name
        //      1: start index to start removing at
        //      2: ending index to stop removing at
        // Returns: true
        //      
        public static Object Trim(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 3);

            Object tempObject;
            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            int startIndex;
            if (!TryResolveIndex(parameters[1], out startIndex))
            {
                throw new ArgumentException(String.Format("Trim failed to resolve startIndex parameter {0}", parameters[1].ToString()));
            }
            int endIndex;
            if (!TryResolveIndex(parameters[2], out endIndex))
            {
                throw new ArgumentException(String.Format("Trim failed to resolve endIndex parameter {0}", parameters[2].ToString()));
            }

            string countKey = CountKeyName(listName);

            int listCount = 0;
            if (astate.TryGet(countKey, out tempObject))
            {
                listCount = (int)tempObject;
            }

            // behavior checks
            if (startIndex < 0)
            {
                startIndex += listCount;
                if (startIndex < 0) startIndex = 0;
            }
            if (endIndex < 0)
            {
                endIndex += listCount;
                if (endIndex < 0) endIndex = 0;
            }

            if (endIndex >= listCount)
                endIndex = listCount - 1;

            if (startIndex >= listCount || startIndex > endIndex)
            {
                Clear(astate, new Object[] { listName });
                return true;
            }

            if (startIndex > 0)
            {
                RemoveRangeHelper(astate, listName, 0, startIndex);

                // We removed the front part of the list, so now decrement our variables by the removed elements.
                listCount -= startIndex;
                Contract.Assume(listCount == (int)astate.Get(countKey), "listCount didn't equal the list count stored in the actor state!");
                endIndex -= startIndex;
            }

            if (endIndex + 1 < listCount)
                RemoveRangeHelper(astate, listName, endIndex + 1, listCount - (endIndex + 1));
            return true;
        }


        // Parameters:
        //      0: list name
        // Returns:
        //      void
        // Notes:
        //    To work well, the client needs to supply a Compare method that knows how to compare T's.
        //    This can be done early and stored in the actor.  Should we allow passing a Comparison<T> or Comparison<Object> here?
        //    We don't currently know that there is a T associated with this actor though on the client.  In fact, for
        //    some clients, we may well always treat this as a List<Object>.
        public static Object Sort(IActorState astate, Object[] parameters)
        {
            Contract.Requires(astate != null);
            Contract.Requires(parameters != null);
            Contract.Requires(parameters.Length == 1);

            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);
            int count = 0;
            Object tempObject;
            if (astate.TryGet(CountKeyName(listName), out tempObject))
            {
                count = (int)tempObject;
            }

            List<Object> items = (List<Object>) Enumerate(astate, new Object[] { listName, 0, -1 });

            Comparison<Object> comparer = GetCompareMethod(astate, listName);
            items.Sort(comparer);

            // Replace items in the list with the right order of elements.  But, if the correct
            // item is already in place, there's no need to change it.
            string leftIndexKey = LeftIndexKeyName(listName);
            int currentIndex = (int) astate.Get(leftIndexKey);
            for (int i = 0; i < items.Count; i++)
            {
                var currentKey = ElementKeyName(listName, currentIndex);
                tempObject = astate.Get(currentKey);
                var element = (Tuple<object, int, int>)tempObject;
                if (comparer.Invoke(element.Item1, items[i]) != 0)
                {
                    element = Tuple.Create(items[i], element.Item2, element.Item3);
                    astate.Set(currentKey, element);
                }
                currentIndex = element.Item3;
            }
            Contract.Assume(currentIndex == -1, "Should have reached the end of the list, but the current index wasn't -1!");

            return null;
        }


        //
        // The following helper functions are to support the internal EmbeddedList class
        // They are not intended to be called by clients.
        // In particular the GetFirst & GetNext methods assume that the 
        // list is not being modified while these calls are being made.
        //

        // Enable or disable Publish calls
        // Parameters:
        //      0: list name
        //      1: 0 - disable, 1 - enable
        // Returns:
        //      null
        internal static object SetAllowPublish(IActorState astate, Object[] parameters)
        {
            Contract.Requires(parameters.Length == 2);

            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);

            int allow;
            if (TryResolveIndex(parameters[1], out allow))
            {
                astate.Set(AllowPublishKeyName(listName), allow);
            }
            return null;
        }

        // Parameters:
        //      0: list name
        // Returns:
        //      string name of first item or null
        // NOTE: Not safe to expose to clients
        internal static object GetFirst(IActorState astate, Object[] parameters)
        {
            Contract.Requires(parameters.Length == 1);

            object tempObject;
            String listName = (String)parameters[0];
            ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);

            var leftIndexKey = LeftIndexKeyName(listName);
            if (astate.TryGet(leftIndexKey, out tempObject))
            {
                int leftIndex = (int)tempObject;
                var currentKey = ElementKeyName(listName, leftIndex);
                return currentKey;
            }

            return null;
        }

        // Parameters:
        //      0: list name
        //      1: previous name (from GetFirst or GetNext)
        // Returns:
        //      Tuple<object, string> (object at name & name of next) or null
        // NOTE: Not safe to expose to clients
        internal static object GetNext(IActorState astate, Object[] parameters)
        {
            Contract.Requires(parameters.Length == 2);

            object tempObject;
            String listName = (String)parameters[0];
            bool exists = ActorKeyType.ValidateKeyType(astate, listName, MyTypeName, false);

            var currentKey = (string)parameters[1];
            if (astate.TryGet(currentKey, out tempObject))
            {
                var element = (Tuple<object, int, int>)tempObject;
                currentKey = ElementKeyName(listName, (int)element.Item3);
                return Tuple.Create<object, string>(element.Item1, currentKey);
            }

            return null;
        }

        // Test if allow publish.
        // If list does not exist, or publish setting not exist, return true
        internal static bool GetAllowPublish(IActorState astate, string listName)
        {
            object tempObject;

            if (astate.TryGet(AllowPublishKeyName(listName), out tempObject))
            {
                return (int)tempObject == 1;
            }
            return true;
        }
    }
}
